3 use Wikimedia\TestingAccessWrapper
;
7 * @covers MessageBlobStore
9 class MessageBlobStoreTest
extends PHPUnit\Framework\TestCase
{
11 use MediaWikiCoversValidator
;
13 protected function setUp() {
15 // MediaWiki tests defaults $wgMainWANCache to CACHE_NONE.
16 // Use hash instead so that caching is observed
17 $this->wanCache
= $this->getMockBuilder( WANObjectCache
::class )
18 ->setConstructorArgs( [ [
19 'cache' => new HashBagOStuff(),
21 'relayer' => new EventRelayerNull( [] )
23 ->setMethods( [ 'makePurgeValue' ] )
26 $this->wanCache
->expects( $this->any() )
27 ->method( 'makePurgeValue' )
28 ->will( $this->returnCallback( function ( $timestamp, $holdoff ) {
29 // Disable holdoff as it messes with testing. Aside from a 0-second holdoff,
30 // make sure that "time" passes between getMulti() check init and the set()
31 // in recacheMessageBlob(). This especially matters for Windows clocks.
32 $ts = (float)$timestamp - 0.0001;
34 return WANObjectCache
::PURGE_VAL_PREFIX
. $ts . ':0';
38 protected function makeBlobStore( $methods = null, $rl = null ) {
39 $blobStore = $this->getMockBuilder( MessageBlobStore
::class )
40 ->setConstructorArgs( [ $rl ] )
41 ->setMethods( $methods )
44 $access = TestingAccessWrapper
::newFromObject( $blobStore );
45 $access->wanCache
= $this->wanCache
;
49 protected function makeModule( array $messages ) {
50 $module = new ResourceLoaderTestModule( [ 'messages' => $messages ] );
51 $module->setName( 'test.blobstore' );
55 /** @covers MessageBlobStore::setLogger */
56 public function testSetLogger() {
57 $blobStore = $this->makeBlobStore();
58 $this->assertSame( null, $blobStore->setLogger( new Psr\Log\
NullLogger() ) );
61 /** @covers MessageBlobStore::getResourceLoader */
62 public function testGetResourceLoader() {
63 // Call protected method
64 $blobStore = TestingAccessWrapper
::newFromObject( $this->makeBlobStore() );
65 $this->assertInstanceOf(
66 ResourceLoader
::class,
67 $blobStore->getResourceLoader()
71 /** @covers MessageBlobStore::fetchMessage */
72 public function testFetchMessage() {
73 $module = $this->makeModule( [ 'mainpage' ] );
74 $rl = new ResourceLoader();
75 $rl->register( $module->getName(), $module );
77 $blobStore = $this->makeBlobStore( null, $rl );
78 $blob = $blobStore->getBlob( $module, 'en' );
80 $this->assertEquals( '{"mainpage":"Main Page"}', $blob, 'Generated blob' );
83 /** @covers MessageBlobStore::fetchMessage */
84 public function testFetchMessageFail() {
85 $module = $this->makeModule( [ 'i-dont-exist' ] );
86 $rl = new ResourceLoader();
87 $rl->register( $module->getName(), $module );
89 $blobStore = $this->makeBlobStore( null, $rl );
90 $blob = $blobStore->getBlob( $module, 'en' );
92 $this->assertEquals( '{"i-dont-exist":"\u29fci-dont-exist\u29fd"}', $blob, 'Generated blob' );
95 public function testGetBlob() {
96 $module = $this->makeModule( [ 'foo' ] );
97 $rl = new ResourceLoader();
98 $rl->register( $module->getName(), $module );
100 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
101 $blobStore->expects( $this->once() )
102 ->method( 'fetchMessage' )
103 ->will( $this->returnValue( 'Example' ) );
105 $blob = $blobStore->getBlob( $module, 'en' );
107 $this->assertEquals( '{"foo":"Example"}', $blob, 'Generated blob' );
110 public function testGetBlobCached() {
111 $module = $this->makeModule( [ 'example' ] );
112 $rl = new ResourceLoader();
113 $rl->register( $module->getName(), $module );
115 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
116 $blobStore->expects( $this->once() )
117 ->method( 'fetchMessage' )
118 ->will( $this->returnValue( 'First' ) );
120 $module = $this->makeModule( [ 'example' ] );
121 $blob = $blobStore->getBlob( $module, 'en' );
122 $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
124 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
125 $blobStore->expects( $this->never() )
126 ->method( 'fetchMessage' )
127 ->will( $this->returnValue( 'Second' ) );
129 $module = $this->makeModule( [ 'example' ] );
130 $blob = $blobStore->getBlob( $module, 'en' );
131 $this->assertEquals( '{"example":"First"}', $blob, 'Cache hit' );
134 public function testUpdateMessage() {
135 $module = $this->makeModule( [ 'example' ] );
136 $rl = new ResourceLoader();
137 $rl->register( $module->getName(), $module );
138 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
139 $blobStore->expects( $this->once() )
140 ->method( 'fetchMessage' )
141 ->will( $this->returnValue( 'First' ) );
143 $blob = $blobStore->getBlob( $module, 'en' );
144 $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
146 $blobStore->updateMessage( 'example' );
148 $module = $this->makeModule( [ 'example' ] );
149 $rl = new ResourceLoader();
150 $rl->register( $module->getName(), $module );
151 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
152 $blobStore->expects( $this->once() )
153 ->method( 'fetchMessage' )
154 ->will( $this->returnValue( 'Second' ) );
156 $blob = $blobStore->getBlob( $module, 'en' );
157 $this->assertEquals( '{"example":"Second"}', $blob, 'Updated blob' );
160 public function testValidation() {
161 $module = $this->makeModule( [ 'foo' ] );
162 $rl = new ResourceLoader();
163 $rl->register( $module->getName(), $module );
165 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
166 $blobStore->expects( $this->once() )
167 ->method( 'fetchMessage' )
168 ->will( $this->returnValueMap( [
169 [ 'foo', 'en', 'Hello' ],
172 $blob = $blobStore->getBlob( $module, 'en' );
173 $this->assertEquals( '{"foo":"Hello"}', $blob, 'Generated blob' );
175 // Now, imagine a change to the module is deployed. The module now contains
176 // message 'foo' and 'bar'. While updateMessage() was not called (since no
177 // message values were changed) it should detect the change in list of
179 $module = $this->makeModule( [ 'foo', 'bar' ] );
180 $rl = new ResourceLoader();
181 $rl->register( $module->getName(), $module );
183 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
184 $blobStore->expects( $this->exactly( 2 ) )
185 ->method( 'fetchMessage' )
186 ->will( $this->returnValueMap( [
187 [ 'foo', 'en', 'Hello' ],
188 [ 'bar', 'en', 'World' ],
191 $blob = $blobStore->getBlob( $module, 'en' );
192 $this->assertEquals( '{"foo":"Hello","bar":"World"}', $blob, 'Updated blob' );
195 public function testClear() {
196 $module = $this->makeModule( [ 'example' ] );
197 $rl = new ResourceLoader();
198 $rl->register( $module->getName(), $module );
199 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
200 $blobStore->expects( $this->exactly( 2 ) )
201 ->method( 'fetchMessage' )
202 ->will( $this->onConsecutiveCalls( 'First', 'Second' ) );
204 $now = microtime( true );
205 $this->wanCache
->setMockTime( $now );
207 $blob = $blobStore->getBlob( $module, 'en' );
208 $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
210 $blob = $blobStore->getBlob( $module, 'en' );
211 $this->assertEquals( '{"example":"First"}', $blob, 'Cache-hit' );
216 $blob = $blobStore->getBlob( $module, 'en' );
217 $this->assertEquals( '{"example":"Second"}', $blob, 'Updated blob' );